﻿/*** Furcadia Installer Class - LibRCH2
 * ---
 * Author: IceDragon <icedragon@quickfox.org>
 * Web:    www.icerealm.org
 * ---
 * 
 * Copyright (c) 2009-2010, IceRealm.org
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   # Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   # Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   # Neither the name of the IceRealm.org nor the names of its contributors
 *     may be used to endorse or promote products derived from this software
 *     without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

using System.IO;
using System.Text;

namespace LibRCH2
{
    public class FurcadiaInstaller
    {
        /*** Constants ***/
        private const int SEARCH_BUFFER_LENGTH = 8192;
        private static long[] RCH2_OFFSETS = { 0x9f400, 0x9fa00, 0x30000, 0x2f000 };

        /*** Static Functions ***/
        public static RCH2Container GetFileContainer(string fileName)
        {
            BinaryReader br = new BinaryReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read));

            // Find where in the installer the RCH2 package resides.
            if (FindContainer(ref br) < 0)
                return null;

            // Read the data.
            return new RCH2Container(ref br);
        }

        public static long FindContainer(ref BinaryReader br)
        {
            // Try the known offsets first.
            foreach (long offset in RCH2_OFFSETS)
            {
                br.BaseStream.Position = offset;
                if (RCH2Container.CheckMagicNumber(ref br))
                {
                    br.BaseStream.Position = offset;
                    return offset;
                }
            }

            // If we didn't find the right magic number yet, go through the
            // entire file. This is kinda tedious.
            br.BaseStream.Position = 0;

            byte[] extended_magic = Encoding.ASCII.GetBytes(RCH2Container.MAGIC_NUMBER + RCH2File.MAGIC_NUMBER);
            byte[] buffer = new byte[0];
            int j = 0;
            int i = 0;
            while (i < extended_magic.Length)
            {
                // If we ran out of buffer, get some more from the file.
                if (j >= buffer.Length)
                {
                    if (br.BaseStream.Position >= br.BaseStream.Length)
                        return -1; // Failed to locate.

                    buffer = br.ReadBytes(SEARCH_BUFFER_LENGTH);
                    j = 0;
                }

                i = (buffer[j++] == extended_magic[i]) ? i + 1 : 0;
            }

            return br.BaseStream.Position - buffer.Length + j - i;
        }
    }
}
